package com.smap.format;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONValue;
import com.smap.core.XY;
import com.smap.vector.Feature;
import com.smap.vector.Geometry;
import com.smap.vector.LineString;
import com.smap.vector.Point;
import com.smap.vector.Polygon;

public class GeoJsonFormat implements Format {

	@SuppressWarnings("unchecked")
	@Override
	public List<Feature> read(String data) {
		JSONValue json = JSONParser.parseStrict(data);
		return (List<Feature>) read(json, null);
	}

	public Object read(JSONValue json, String type) {
		Object results = null;

		if ("Geometry".equals(type)) {
			results = this.parseGeometry(json);
		} else if ("Feature".equals(type)) {
			results = this.parseFeature(json);
		} else { // FeatureCollection
			ArrayList<Feature> feats = new ArrayList<Feature>();
			results = feats;
			String objType = getType(json);
			if ("Feature".equals(objType)) {
				feats.add(this.parseFeature(json));
			} else if ("FeatureCollection".equals(objType)) { 
				JSONArray featJsons = json.isObject().get("features").isArray();
				for (int i = 0; i < featJsons.size(); i++) {
					JSONValue featJson = featJsons.get(i);
					Feature feat = parseFeature(featJson);
					feats.add(feat);
				}
			} else {// geometry
				Geometry geom = this.parseGeometry(json);
				feats.add(new Feature(geom, null));
			}
		}

		return results;
	}

	private Feature parseFeature(JSONValue json) {
		Feature feat = new Feature();
		// properties
		JSONObject props = json.isObject().get("properties").isObject();
		for (String key : props.keySet()) {
			try {
				feat.properties.put(key, props.get(key).isString()
						.stringValue());
			} catch (Exception e) {
			}
		}
		// geometry
		feat.geom = parseGeometry(json.isObject().get("geometry"));

		return feat;
	}

	/**
	 * only support Point, LineString, Polygon at this moment and doesn't
	 * support hole in polygon
	 * 
	 * @param json
	 * @return
	 */
	private Geometry parseGeometry(JSONValue json) {
		Geometry geom = null;
		String type = getType(json);
		JSONValue coordinates = json.isObject().get("coordinates");

		if ("Point".equals(type)) {
			JSONArray c = coordinates.isArray();
			geom = new Point(c.get(0).isNumber().doubleValue(), c.get(1)
					.isNumber().doubleValue());
		} else if ("LineString".equals(type)) {
			geom = new LineString();
			JSONArray c = coordinates.isArray();
			for (int i = 0; i < c.size(); i++) {
				JSONArray d = c.get(i).isArray();
				XY xy = new XY(d.get(0).isNumber().doubleValue(), d.get(1)
						.isNumber().doubleValue());
				geom.add(xy);
			}
		} else if ("Polygon".equals(type)) {
			geom = new Polygon();
			JSONArray c = coordinates.isArray().get(0).isArray();
			for (int i = 0; i < c.size(); i++) {
				try {
					JSONArray d = c.get(i).isArray();
					XY xy = new XY(d.get(0).isNumber().doubleValue(), d.get(1)
							.isNumber().doubleValue());
					geom.add(xy);
				} catch (Exception e) {

				}
			}
		}

		return geom;
	}

	@Override
	public String write(List<Feature> feats) {
		// TODO Auto-generated method stub
		return null;
	}

	private String getType(JSONValue jObj) {
		String ret = null;
		try {
			JSONValue type = ((JSONObject) jObj).get("type");
			ret = type.isString().stringValue();
		} catch (Exception e) {
		}
		return ret;
	}

}
